package org.kongqian.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import org.kongqian.basic.config.RegisterNoticeRabbitmqConfig;
import org.kongqian.basic.constants.WxConstants;
import org.kongqian.basic.utils.AjaxResult;
import org.kongqian.basic.utils.HttpClientUtils;
import org.kongqian.basic.utils.MD5Utils;
import org.kongqian.user.domain.Logininfo;
import org.kongqian.user.domain.User;
import org.kongqian.user.domain.Wxuser;
import org.kongqian.user.dto.RegisterNoticeDto;
import org.kongqian.user.dto.UserDTO;
import org.kongqian.user.dto.WechatBindDTO;
import org.kongqian.user.mapper.LogininfoMapper;
import org.kongqian.user.mapper.UserMapper;
import org.kongqian.user.mapper.WxuserMapper;
import org.kongqian.user.service.IUserService;
import org.kongqian.basic.service.impl.BaseServiceImpl;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.h2.H2ConsoleProperties;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author kq
 * @since 2022-11-15
 */
@Service
public class UserServiceImpl extends BaseServiceImpl<User> implements IUserService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private WxuserMapper wxuserMapper;

    @Override
    @Transactional
    public void userRegister(UserDTO dto) {
        String mobile = dto.getMobile();
        String phoneCode = dto.getPhoneCode();
        String userName = dto.getUserName();
        String password = dto.getPassword();
        String confirmPassword = dto.getConfirmPassword();
        //参数非空校验
        if (StringUtils.isEmpty(mobile) ||StringUtils.isEmpty(phoneCode) ||
            StringUtils.isEmpty(userName) || StringUtils.isEmpty(password) ||StringUtils.isEmpty(confirmPassword)){
            throw new RuntimeException("注册信息不能为空！");
        }
        //判断手机验证码是否正确
        String mobileCode = (String)redisTemplate.opsForValue().get("verify_code_texting" + mobile);
        //判断手机验证码是否已经过期
        if (StringUtils.isEmpty(mobileCode)){
            throw new RuntimeException("手机验证码已过期,请重新获取！");
        }

        //判断手机验证码是否正确
        String splitMobile = mobileCode.split(":")[0];
        if (!splitMobile.equalsIgnoreCase(phoneCode)){
            throw new RuntimeException("手机验证码输入错误！");
        }
        //判断密码两次是否一致
        if (!password.equals(confirmPassword)){
            throw new RuntimeException("两次密码输入不一致！");
        }
        //判断用户名是否已经存在
        Logininfo logininfo=logininfoMapper.selectByUsername(userName);
        if (Objects.nonNull(logininfo)){
            throw new RuntimeException("该用户已被注册！");
        }
        //前端传来的明文明码和盐值加密
            //颜值 随机码
        String salt = UUID.randomUUID().toString();
        String passwordByMd5 = MD5Utils.encrypByMd5(salt + password);

        //先保存在loginingo表中
        Logininfo logininfo1 = new Logininfo();
        logininfo1.setUsername(userName);
        logininfo1.setDisable(1);
        logininfo1.setPassword(passwordByMd5);
        logininfo1.setPhone(mobile);
        logininfo1.setSalt(salt);
        logininfo1.setType(1);
        logininfoMapper.insert(logininfo1);

        //再保存在user表中
        User user = new User();
        user.setUsername(userName);
        user.setPhone(mobile);
        user.setSalt(salt);
        user.setPassword(passwordByMd5);
        user.setState(2);
        user.setCreatetime(new Date());
        user.setLogininfoId(logininfo1.getId());
        userMapper.insert(user);

        //注册成功后发短信/邮件
        rabbitTemplate.convertAndSend(RegisterNoticeRabbitmqConfig.EXCHANGE_TOPICS_INFORM,
                "inform.sms",
                new RegisterNoticeDto(mobile,"收到短信通知：你好！你注册的账号已经完成，可以正常使用了！"));  //收件人（phone） 消息内容
        rabbitTemplate.convertAndSend(RegisterNoticeRabbitmqConfig.EXCHANGE_TOPICS_INFORM,
                "inform.email",
                new RegisterNoticeDto(mobile,"收到邮件通知：你好！你注册的账号已经完成，可以正常使用了！"));  //收件人（email） 消息内容

    }

    @Override
    @Transactional
    public AjaxResult wechatBind(WechatBindDTO dto) {
        Logininfo logininfo=null;
        //参数的非空校验
        String mobile = dto.getMobile();
        String verifyCode = dto.getVerifyCode();
        String openid = dto.getOpenid();
        String accessToken = dto.getAccessToken();
        if (StringUtils.isEmpty(mobile) || StringUtils.isEmpty(verifyCode) ||StringUtils.isEmpty(openid) ||StringUtils.isEmpty(accessToken)){
            throw new RuntimeException("请填写完整信息！");
        }
        //判断手机验证码是否正确
        String bindPhoneCode =(String) redisTemplate.opsForValue().get("bind_code_texting" + mobile);
        if (StringUtils.isEmpty(bindPhoneCode)){
            throw new RuntimeException("手机验证码已过期，请重新获取！");
        }
        bindPhoneCode = bindPhoneCode.split(":")[0];
        if (!verifyCode.equalsIgnoreCase(bindPhoneCode)){
            throw new RuntimeException("手机验证码输入不正确，请重新输入！");
        }
        //判断手机号是否已经注册 user
        User user=userMapper.selectByMobile(mobile);
        if (Objects.nonNull(user)){
            //注册
            //判断是否已经绑定微信 根据userId去查
            Long userId = user.getId();
            Wxuser wxuser =wxuserMapper.selectByUserId(userId);
            if (Objects.nonNull(wxuser)){
                //绑定就返回已绑定其他微信
                throw new RuntimeException("该手机号已绑定其他微信！");
            }else {
                //没有绑定就绑定
                //获取微信用户信息
                wxuser=getWechatUserInfo(accessToken,openid);
                wxuser.setUserId(user.getId());
                wxuserMapper.insert(wxuser);
                //到这里我们已经绑定好了，接下来就是免登录，要给前端返回登录信息，做登录拦截和展示用户信息
                logininfo=logininfoMapper.selectLoginInfoByUserId(user.getId());
            }
        }else {
            //没有注册 就创建登录信息 用户信息 微信信息
            //如果没有注册，我们就默认给用户初始化数据
            //创建loginInfo信息
            logininfo=initLoginInfo(mobile);
            logininfoMapper.insert(logininfo);
            //创建user信息
            user=initUserInfo(logininfo);
            userMapper.insert(user);
            //绑定微信
            Wxuser wxuser = getWechatUserInfo(accessToken, openid);
            wxuser.setUserId(user.getId());
            wxuserMapper.insert(wxuser);
        }
        //最后来免登录
        //将登录信息以token为key的形式存到redis中
        //返回前端登录信息和token 登录信息用来在前端展示 token用来做登录拦截
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, logininfo,30, TimeUnit.MINUTES);
        HashMap<String, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("token", token);
        objectObjectHashMap.put("loginInfo", logininfo);
        return AjaxResult.getResult().setObject(objectObjectHashMap);
    }

    private User initUserInfo(Logininfo logininfo) {
        //user里的数据和loginfo的数据是一样的，所以直接复制
        User user = new User();
        BeanUtils.copyProperties(logininfo, user);
        //没有的单独设置
        user.setLogininfoId(logininfo.getId());
        user.setCreatetime(new Date());
        user.setState(2);
        return user;
    }

    private Logininfo initLoginInfo(String mobile) {
        Logininfo logininfo = new Logininfo();
        logininfo.setUsername(UUID.randomUUID().toString());
        logininfo.setType(1);
        logininfo.setPhone(mobile);
        logininfo.setDisable(1);
        //盐值
        String salt =UUID.randomUUID().toString();
        String password=MD5Utils.encrypByMd5(salt+"123456");
        logininfo.setSalt(salt);
        logininfo.setPassword(password);
        return logininfo;
    }

    private Wxuser getWechatUserInfo(String accessToken,String openid){
        //根据accessToken openid 去获取微信用户信息
        String getUserUrl=WxConstants.GET_USER_URL
                   .replace("ACCESS_TOKEN", accessToken)
                   .replace("OPENID", openid);
        String WechatUserInfo = HttpClientUtils.httpGet(getUserUrl);
        //将获取的微信用户信息转换为wxuser对象
        Wxuser wxuser=WechatUserInfo2Obj(WechatUserInfo);
        return wxuser;
    }

    private Wxuser WechatUserInfo2Obj(String wechatUserInfo) {
        JSONObject weChatUserInfoObject = JSONObject.parseObject(wechatUserInfo);
        if (!Objects.nonNull(weChatUserInfoObject)){
            throw new RuntimeException("授权已过期！请重新授权！");
        }
        Wxuser wxuser = new Wxuser();
        wxuser.setOpenid(weChatUserInfoObject.getString("openid"));
        wxuser.setSex(weChatUserInfoObject.getInteger("sex"));
        wxuser.setAddress(weChatUserInfoObject.getString("country"));
        wxuser.setNickname(weChatUserInfoObject.getString("nickname"));
        wxuser.setUnionid(weChatUserInfoObject.getString("unionid"));
        wxuser.setHeadimgurl(weChatUserInfoObject.getString("headimgurl"));
        return wxuser;
    }
}
